package com.swak.metrics.impl;

import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.codahale.metrics.Counter;
import com.codahale.metrics.ExponentiallyDecayingReservoir;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.swak.metrics.json.Helper;
import com.swak.metrics.json.JsonObject;

public class AbstractMetrics {

	protected final MetricRegistry registry;
	protected final String baseName;

	protected AbstractMetrics(MetricRegistry registry, String baseName) {
		this.registry = registry;
		this.baseName = baseName;
	}

	/**
	 * Will return the metrics that correspond with a given base name.
	 *
	 * @return the map of metrics where the key is the name of the metric (excluding
	 *         the base name) and the value is the json data representing that
	 *         metric
	 */
	public JsonObject metrics(String baseName) {
		Map<String, Object> map = registry.getMetrics().entrySet().stream().filter(e -> e.getKey().startsWith(baseName))
				.collect(Collectors.toMap(e -> projectName(e.getKey()),
						e -> Helper.convertMetric(e.getValue(), TimeUnit.SECONDS, TimeUnit.MILLISECONDS)));
		return new JsonObject(map);
	}

	/**
	 * Will return the metrics that correspond with this measured object.
	 *
	 * @see #metrics(String)
	 */
	public JsonObject metrics() {
		return metrics(baseName());
	}

	String projectName(String name) {
		String baseName = baseName();
		return name.substring(baseName.length() + 1);
	}

	protected MetricRegistry registry() {
		return registry;
	}

	public String baseName() {
		return baseName;
	}

	protected String nameOf(String... names) {
		return MetricRegistry.name(baseName, names);
	}

	public boolean isEnabled() {
		return true;
	}

	/**
	 * 这个是定制性最大的,但是需要有一个参考对象（例如队列的总数）<br>
	 * 
	 * 仪表图 比率(实时的数据)：<br>
	 * RatioGauge gauge = new RatioGauge() {<br>
	 * protected Ratio getRatio() {<br>
	 * return Ratio.of(counter.getCount(), 10);<br>
	 * }<br>
	 * };<br>
	 * registry.register("gauge", gauge);<br>
	 * 
	 * 完成率：实时计算 Ratio.of(counter.getCount(), 10);<br>
	 * 可以根据实际的情况设置这两个值<br>
	 * 
	 * "value":1.0<br>
	 * 
	 * @param <T>
	 * @param gauge
	 * @param names
	 * @return
	 */
	protected <T> Gauge<T> gauge(Gauge<T> gauge, String... names) {
		try {
			return registry.register(nameOf(names), gauge);
		} catch (IllegalArgumentException e) {
			return gauge;
		}
	}

	/**
	 * 关注正在执行的个数<br>
	 * 数量 可以表示调用次数，或者正在调用的数量<br>
	 * 
	 * "count":"10",<br>
	 * 
	 * @param names
	 * @return
	 */
	protected Counter counter(String... names) {
		try {
			return registry.counter(nameOf(names));
		} catch (Exception e) {
			return new Counter();
		}
	}

	/**
	 * 关注的数据本身<br>
	 * 
	 * 直方图（数据值的分布）: 最大值,最小值,平均值,中值 <br>
	 * histogram.update(i);<br>
	 * 
	 * 数据数量:<br>
	 * "count":"10",<br>
	 * 
	 * 数据的值分布:<br>
	 * "p50":5.0,<br>
	 * "p75":7.0,<br>
	 * "p95":9.0,<br>
	 * "p98":9.0,<br>
	 * "p99":9.0,<br>
	 * "p999":9.0,<br>
	 * 
	 * 数据最大值最小值分布:<br>
	 * "min":"0",<br>
	 * "mean":4.644117668532804,<br>
	 * "max":"9",<br>
	 * "stddev":2.8640747226186396<br>
	 * 
	 * @param names
	 * @return
	 */
	protected Histogram histogram(String... names) {
		try {
			return registry.histogram(nameOf(names));
		} catch (Exception e) {
			return new Histogram(new ExponentiallyDecayingReservoir());
		}
	}

	/**
	 * 速率和用时 :例如方法的执行统计<br>
	 * meter.mark(); <br>
	 * 速率（QPS） calls/s ： 这个指标和Timer 中的完成率部分是一样的概念，数据也是一样的，此例子来至不同的统计<br>
	 * 
	 * "count":"10",<br>
	 * "mean_rate":0.956618041452747,<br>
	 * "m15_rate":0.8011080303990207,<br>
	 * "m1_rate":0.8159911170741354,<br>
	 * "m5_rate":0.8033057092356766<br>
	 * 
	 * @param names
	 * @return
	 */
	protected Meter meter(String... names) {
		try {
			return registry.meter(nameOf(names));
		} catch (Exception e) {
			return new Meter();
		}
	}

	/**
	 * 关注的执行的统计情况<br>
	 * 速率和用时 :例如方法的执行统计<br>
	 * 
	 * Timer.Context context = timer.time();<br>
	 * do Something <br>
	 * context.stop();<br>
	 * 
	 * 数量： "count":"10",<br>
	 * 
	 * 最大、最小、平均，方差（用时 MS） ：<br>
	 * "max":1947.8523,<br>
	 * "mean":1225.402374631002,<br>
	 * "stddev":583.1300369403967, <br>
	 * "min":383.8867,<br>
	 * 
	 * 用时统计分析（MS）：<br>
	 * "p50":1612.8075, 50% 的 用时1612.8075<br>
	 * "p75":1716.1978,<br>
	 * "p95":1947.8523,<br>
	 * "p98":1947.8523,<br>
	 * "p99":1947.8523,<br>
	 * "p999":1947.8523,<br>
	 * 
	 * 速率（QPS） calls/s ： <br>
	 * "m1_rate":0.8, 1分钟内 8次调用每秒<br>
	 * "m5_rate":0.8<br>
	 * "m15_rate":0.8,<br>
	 * "mean_rate":0.8198866121412007, <br>
	 * 
	 * @param names
	 * @return
	 */
	protected Timer timer(String... names) {
		try {
			return registry.timer(nameOf(names));
		} catch (Exception e) {
			return new Timer();
		}
	}

	protected ThroughputMeter throughputMeter(String... names) {
		try {
			return RegistryHelper.throughputMeter(registry, nameOf(names));
		} catch (Exception e) {
			return new ThroughputMeter();
		}
	}

	protected ThroughputTimer throughputTimer(String... names) {
		try {
			return RegistryHelper.throughputTimer(registry, nameOf(names));
		} catch (Exception e) {
			return new ThroughputTimer();
		}
	}

	protected void remove(String... names) {
		registry.remove(nameOf(names));
	}

	protected void removeAll() {
		registry.removeMatching((name, metric) -> name.startsWith(baseName));
	}
}
